package com.apes.fn.scm.merchant.account.service;

import com.alibaba.fastjson.JSONObject;
import com.apes.fn.scm.merchant.account.model.MerchantAccountSettlement;
import com.apes.fn.scm.merchant.account.model.SettlementAutoCreateLog;
import com.apes.fn.scm.merchant.account.repository.AccountSettlementRepository;
import com.apes.fn.scm.merchant.account.repository.SettlementAutoCreateLogRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apestech.framework.json.JSONArray;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Title: ScheduleSettlementService
 * @Author fj
 * @Package com.apes.fn.scm.merchant.account.service
 * @Date 2023/8/9 13:55
 * @description: 对账单定时任务
 */
@Service("scheduleSettlementService")
public class ScheduleSettlementService extends DomainService {

    @Autowired
    private AccountSettlementService accountSettlementService;

    @Autowired
    private AccountSettlementRepository accountSettlementRepository;

    @Autowired
    private SettlementAutoCreateLogRepository settlementAutoCreateLogRepository;

    @Autowired
    private TransactionTemplate transactionTemplate;

    //月结
    public final static String MONTHLY = "001416";

    //半月结
    public final static String HALF_MONTH = "001420";

    /**
     * 对账单自动创建 --月结定时任务（生成上个月1号 ~ 最后一天的对账单及 16号 ~ 最后一天的对账单）
     * 6号执行
     * 同时生成下半月的半月结账单
     * @param request
     */
    public void monthlySettlement(SimpleRequest request){
        //获取月结算商户数据
        List<Map<String, Object>> monthlyMap = accountSettlementRepository.queryAutoCreateSettlement(MONTHLY);
        JSONArray array = getMonthlySettlementDate(monthlyMap);
        array.forEach(item -> {
            JSONObject jsonObject = (JSONObject) item;
            saveSettlement(jsonObject,MONTHLY);
        });

        //获取半月结商户数据(16号 ~ 最后一天)
        List<Map<String, Object>> halfMonthMap = accountSettlementRepository.queryAutoCreateSettlement(HALF_MONTH);
        JSONArray afterHalfSettlements = getAfterHalfSettlementDate(halfMonthMap);
        afterHalfSettlements.forEach(item -> {
            JSONObject jsonObject = (JSONObject) item;
            saveSettlement(jsonObject,HALF_MONTH);
        });
    }

    /**
     * 对账单自动创建 --半个月结定时任务（生成1号 ~ 15号的对账单）
     * 17号执行
     * @param request
     */
    public void halfSettlement(SimpleRequest request){
        //获取半月结商户数据
        List<Map<String, Object>> map = accountSettlementRepository.queryAutoCreateSettlement(HALF_MONTH);
        JSONArray array = getBeforeHalfSettlementDate(map);
        array.forEach(item -> {
            JSONObject jsonObject = (JSONObject) item;
            saveSettlement(jsonObject,HALF_MONTH);
        });
    }

    /**
     * 删除已生成对账单数据
     * @param request:{"createDate":"2023-08-19 00:00:00.000","createEndDate":"2023-08-19 23:59:59.000"}
     */
    public void deleteAutoSettlement(SimpleRequest request){
        com.alibaba.fastjson.JSONObject requestJO = request.getJO();
        Date createDate = DateUtil.dateToDate(requestJO.getDate("createDate"), DateUtil.SHOW_DATETIME_MILLI_FORMAT);
        Date createEndDate = DateUtil.dateToDate(requestJO.getDate("createEndDate"), DateUtil.SHOW_DATETIME_MILLI_FORMAT);

        List<MerchantAccountSettlement> settlements = accountSettlementRepository.findAll(
                JpaDsl.toCriteriaIgnoreNull("createDate", "GTE", createDate,"createDate", "LTE", createEndDate, "autoFlag", "EQ", "1"));
        if (!CollectionUtils.isEmpty(settlements)){
            settlements.forEach(item -> {
                SimpleRequest simpleRequest = new SimpleRequest();
                simpleRequest.setData(MapUtil.mapped(item));
                accountSettlementService.delete(simpleRequest);
            });
        }
    }

    /**
     * 保存数据
     * @param object
     */
    private void saveSettlement(JSONObject object, String type){
        if (DateUtil.dateCompare(object.getDate("reconcileBeginDate"),object.getDate("reconcileEndDate")) == 1){
            return;
        }
        SimpleRequest generateRequest = new SimpleRequest();
        generateRequest.setData(object);
        try {
            execute(()-> {
                MerchantAccountSettlement settlementData = accountSettlementService.generateSettlementData(generateRequest);
                setSettlementData(settlementData, object);
                SimpleRequest saveRequest = new SimpleRequest();
                saveRequest.setData(settlementData);
                accountSettlementService.save(saveRequest);
            });
        } catch (Exception e) {
            //保存错误信息
            execute(()-> saveLog(object, e.toString(), type));
        }
    }

    /**
     * 对账单属性设置
     * 设置需额外设置的数值
     * @param settlement
     */
    private void setSettlementData(MerchantAccountSettlement settlement,JSONObject object){
        //标识为定时任务自动创建
        settlement.setAutoFlag(1);
        settlement.setMerchant(getBean(PartyRoleRepository.class).findOne(object.getString("merchantId")));
        if (!CollectionUtils.isEmpty(settlement.getMerchantAccountSubjects())){
            settlement.getMerchantAccountSubjects().forEach(item -> {
                if (item.getPast() == false){
                    item.getAmount();
                    item.setActualPayable(item.getActualPayable());
                    item.setDifference(item.getDifference());
                }
            });
        }
    }

    /**
     * 获取结算起止时间---半月结(1号 ~ 15号)
     * @param maps
     * @return
     */
    private JSONArray getBeforeHalfSettlementDate(List<Map<String, Object>> maps){
        JSONArray array = new JSONArray();
        if (!CollectionUtils.isEmpty(maps)){
            //获取当月15号
            Date fifteen = DateUtil.getCustomDate(0, 15, 23, 59, 59);

            maps.forEach(item -> {
                JSONObject request = new JSONObject();
                //获取上期对账单信息
                String merchantid = (String) item.get("MERCHANTID");
                List<MerchantAccountSettlement> settlement =  accountSettlementRepository.findByMaxReconcileEndDate(merchantid);
                Date firstDay = null;
                if (CollectionUtils.isEmpty(settlement)){
                    //没有上一期对账单结算期起直接获取1号
                    firstDay = DateUtil.getMonthFirstDay(new Date());
                }else {
                    //根据上一期对账单结算期止 +1 获取本期对账单结算期起
                    MerchantAccountSettlement accountSettlement = settlement.get(0);
                    firstDay = DateUtil.add(accountSettlement.getReconcileEndDate(), Calendar.DAY_OF_MONTH, 1);
                }
                request.put("reconcileBeginDate",DateUtil.format(firstDay,DateUtil.SHOW_DATETIME_MILLI_FORMAT));
                request.put("reconcileEndDate",DateUtil.format(fifteen,DateUtil.SHOW_DATETIME_MILLI_FORMAT));
                request.put("merchantId",merchantid);
                request.put("contractId",item.get("CONTRACTID"));
                request.put("companyId",item.get("COMPANYID"));
                array.add(request);
            });
        }
        return array;
    }

    /**
     * 获取结算起止时间---月结(上个月1号 ~ 最后一天)
     * @param maps
     * @return
     */
    private JSONArray getMonthlySettlementDate(List<Map<String, Object>> maps){
        JSONArray array = new JSONArray();
        if (!CollectionUtils.isEmpty(maps)){
            //获取上个月第一天和最后一天
            Date beforeMonth = DateUtil.getCustomDate(-1, 01, 00, 00, 00);
            Date lastDay = DateUtil.getMonthLastDay(beforeMonth);

            maps.forEach(item -> {
                JSONObject request = new JSONObject();
                //获取上期对账单信息
                String merchantid = (String) item.get("MERCHANTID");
                List<MerchantAccountSettlement> settlement =  accountSettlementRepository.findByMaxReconcileEndDate(merchantid);
                Date firstDay = null;
                if (CollectionUtils.isEmpty(settlement)){
                    //没有上一期对账单结算期起直接获取1号
                    firstDay = beforeMonth;
                }else {
                    //根据上一期对账单结算期止 +1 获取本期对账单结算期起
                    MerchantAccountSettlement accountSettlement = settlement.get(0);
                    firstDay = DateUtil.add(accountSettlement.getReconcileEndDate(), Calendar.DAY_OF_MONTH, 1);
                }
                request.put("reconcileBeginDate",DateUtil.format(firstDay,DateUtil.SHOW_DATETIME_MILLI_FORMAT));
                request.put("reconcileEndDate",DateUtil.format(lastDay,DateUtil.SHOW_DATETIME_MILLI_FORMAT));
                request.put("merchantId",merchantid);
                request.put("contractId",item.get("CONTRACTID"));
                request.put("companyId",item.get("COMPANYID"));
                array.add(request);
            });
        }
        return array;
    }

    /**
     * 获取结算起止时间---半月结(16号 ~ 最后一天)
     * @param maps
     * @return
     */
    public JSONArray getAfterHalfSettlementDate(List<Map<String, Object>> maps){
        JSONArray array = new JSONArray();
        if (!CollectionUtils.isEmpty(maps)){
            //获取上个月16号和最后一天
            Date beforeMonth = DateUtil.getCustomDate(-1, 16, 00, 00, 00);
            Date lastDay = DateUtil.getMonthLastDay(beforeMonth);

            maps.forEach(item -> {
                JSONObject request = new JSONObject();
                //获取上期对账单信息
                String merchantid = (String) item.get("MERCHANTID");
                List<MerchantAccountSettlement> settlement =  accountSettlementRepository.findByMaxReconcileEndDate(merchantid);
                Date firstDay = null;
                if (CollectionUtils.isEmpty(settlement)){
                    //没有上一期对账单结算期起直接获取16号
                    firstDay = beforeMonth;
                }else {
                    //根据上一期对账单结算期止 +1 获取本期对账单结算期起
                    MerchantAccountSettlement accountSettlement = settlement.get(0);
                    firstDay = DateUtil.add(accountSettlement.getReconcileEndDate(), Calendar.DAY_OF_MONTH, 1);
                }
                request.put("reconcileBeginDate",DateUtil.format(firstDay,DateUtil.SHOW_DATETIME_MILLI_FORMAT));
                request.put("reconcileEndDate",DateUtil.format(lastDay,DateUtil.SHOW_DATETIME_MILLI_FORMAT));
                request.put("merchantId",merchantid);
                request.put("contractId",item.get("CONTRACTID"));
                request.put("companyId",item.get("COMPANYID"));
                array.add(request);
            });
        }
        return array;
    }


    /**
     * 保存创建错误日志
     * @param data
     * @param error
     */
    public void saveLog(JSONObject data, String error,String type){
        SettlementAutoCreateLog autoCreateLog = new SettlementAutoCreateLog();
        autoCreateLog.setCondition(data.toString());
        autoCreateLog.setError(error);
        autoCreateLog.setType(type);
        settlementAutoCreateLogRepository.saveAndFlush(autoCreateLog);
    }

    public void execute(Callback callback) {
        transactionTemplate.execute(status -> {
            try {
                callback.execute();
                return null;
            } catch (Exception e) {
                status.isRollbackOnly();
                throw e;
            }
        });
    }

    @FunctionalInterface
    public interface Callback {
        @Nullable
        void execute();
    }

}
